home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 16 / Example 16.1 / app.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-13  |  26.9 KB  |  1,003 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 16.1: The Game!                                    //
  3. // Written by: C. Granberg, 2006                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "shader.h"
  10. #include "terrain.h"
  11. #include "camera.h"
  12. #include "mouse.h"
  13. #include "player.h"
  14. #include "effect.h"
  15. #include "particles.h"
  16. #include "sound.h"
  17. #include "avi.h"
  18.  
  19. //Effect Pool
  20. extern std::vector<EFFECT*> effects;
  21.  
  22. #define SINGLE_PLAYER 0
  23. #define MULTI_PLAYER 1
  24.  
  25. class APPLICATION
  26. {
  27.     public:
  28.         APPLICATION();
  29.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  30.         HRESULT Update(float deltaTime);
  31.         HRESULT Render();
  32.         HRESULT Cleanup();
  33.         HRESULT Quit();
  34.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  35.  
  36.         void MainMenu();
  37.         void Load(int mode);
  38.         void AddPlayers(int noPlayers);
  39.         void FogOfWar();
  40.         void UpdateMiniMap();
  41.         void RenderMiniMap(RECT dest);
  42.         void Groups();
  43.  
  44.     private:
  45.         IDirect3DDevice9* m_pDevice; 
  46.         TERRAIN m_terrain;
  47.         CAMERA m_camera;
  48.         MOUSE m_mouse;
  49.         std::vector<PLAYER*> m_players;
  50.         
  51.         ID3DXFont *m_pFont, *m_pFontBig;
  52.         int m_thisPlayer;
  53.         float m_gameSpeed;
  54.         HWND m_mainWindow;
  55.         ID3DXLine *m_pLine;
  56.         DWORD m_groupTime;
  57.         
  58.         //Sound
  59.         SOUND m_sound;
  60.         MP3 m_songs[2];
  61.         float m_volumes[2], m_gameOverTime;
  62.         int m_playingSong;
  63.  
  64.         //Intro
  65.         MP3 *m_pIntroSong;
  66.         AVI *m_pIntroMovie;
  67.         bool m_playingIntro;
  68.  
  69.         //Fog-of-War variables
  70.         IDirect3DTexture9 *m_pVisibleTexture, *m_pVisitedTexture; 
  71.         IDirect3DTexture9 *m_pMenuTexture, *m_pMenuButtons;
  72.         SHADER m_visitedShader, m_FogOfWarShader;
  73.         ID3DXSprite *m_pSprite;
  74.         bool m_firstFogOfWar;
  75.         bool m_menu, m_gameOver;
  76.  
  77.         //Minimap
  78.         IDirect3DTexture9 *m_pMiniMap;
  79.         IDirect3DTexture9 *m_pMiniMapBorder;
  80.         SHADER m_miniMapShader;
  81.         RECT m_miniMapRect;
  82. };
  83.  
  84. D3DRECT SetRect(long x1, long y1, long x2, long y2)
  85. {
  86.     D3DRECT r;
  87.     r.x1 = x1;
  88.     r.y1 = y1;
  89.     r.x2 = x2;
  90.     r.y2 = y2;
  91.     return r;
  92. }
  93.  
  94. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  95. {
  96.     APPLICATION app;
  97.  
  98.     if(FAILED(app.Init(hInstance, 800, 600, false)))return 0;
  99.  
  100.     MSG msg;
  101.     memset(&msg, 0, sizeof(MSG));
  102.     int startTime = timeGetTime(); 
  103.  
  104.     while(msg.message != WM_QUIT)
  105.     {
  106.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  107.         {
  108.             ::TranslateMessage(&msg);
  109.             ::DispatchMessage(&msg);
  110.         }
  111.         else
  112.         {    
  113.             int t  = timeGetTime();
  114.             float deltaTime = (t - startTime) * 0.001f;
  115.  
  116.             app.Update(deltaTime);
  117.             app.Render();
  118.  
  119.             startTime = t;
  120.         }
  121.     }
  122.  
  123.     app.Cleanup();
  124.  
  125.     return msg.wParam;
  126. }
  127.  
  128. APPLICATION::APPLICATION()
  129. {
  130.     m_pDevice = NULL; 
  131.     m_mainWindow = 0;
  132.     srand(GetTickCount());
  133.     m_thisPlayer = 0;
  134.     m_pLine = NULL;
  135.     m_firstFogOfWar = true;
  136.     m_gameSpeed = 2.0f;
  137.     m_pIntroSong = NULL;
  138.     m_pIntroMovie = NULL;
  139.     m_menu = false;
  140.     m_groupTime = GetTickCount();
  141.  
  142.     m_pVisibleTexture = m_pVisitedTexture = m_pMiniMap = NULL;
  143.     m_pMenuTexture = m_pMenuButtons = NULL;
  144.     m_pMiniMapBorder = NULL;
  145. }
  146.  
  147. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  148. {
  149.     debug.Print("Application initiated");
  150.  
  151.     //Create Window Class
  152.     WNDCLASS wc;
  153.     memset(&wc, 0, sizeof(WNDCLASS));
  154.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  155.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  156.     wc.hInstance     = hInstance;
  157.     wc.lpszClassName = "D3DWND";
  158.  
  159.     //Register Class and Create new Window
  160.     RegisterClass(&wc);
  161.     m_mainWindow = CreateWindow("D3DWND", "Example 16.1: The Game!", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  162.     SetCursor(NULL);
  163.     ShowWindow(m_mainWindow, SW_SHOW);
  164.     UpdateWindow(m_mainWindow);
  165.  
  166.     //Create IDirect3D9 Interface
  167.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  168.  
  169.     if(d3d9 == NULL)
  170.     {
  171.         debug.Print("Direct3DCreate9() - FAILED");
  172.         return E_FAIL;
  173.     }
  174.  
  175.     //Check that the Device supports what we need from it
  176.     D3DCAPS9 caps;
  177.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  178.  
  179.     //Hardware Vertex Processing or not?
  180.     int vp = 0;
  181.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  182.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  183.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  184.  
  185.     //Check vertex & pixelshader versions
  186.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  187.     {
  188.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  189.     }
  190.  
  191.     //Set D3DPRESENT_PARAMETERS
  192.     D3DPRESENT_PARAMETERS d3dpp;
  193.     d3dpp.BackBufferWidth            = width;
  194.     d3dpp.BackBufferHeight           = height;
  195.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  196.     d3dpp.BackBufferCount            = 1;
  197.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  198.     d3dpp.MultiSampleQuality         = 0;
  199.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  200.     d3dpp.hDeviceWindow              = m_mainWindow;
  201.     d3dpp.Windowed                   = windowed;
  202.     d3dpp.EnableAutoDepthStencil     = true; 
  203.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  204.     d3dpp.Flags                      = 0;
  205.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  206.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  207.  
  208.     //Create the IDirect3DDevice9
  209.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  210.                                  vp, &d3dpp, &m_pDevice)))
  211.     {
  212.         debug.Print("Failed to create IDirect3DDevice9");
  213.         return E_FAIL;
  214.     }
  215.  
  216.     //Release IDirect3D9 interface
  217.     d3d9->Release();
  218.  
  219.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  220.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  221.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  222.  
  223.     D3DXCreateFont(m_pDevice, 32, 0, 0, 1, false,  
  224.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  225.                    DEFAULT_PITCH | FF_DONTCARE, "Arial Black", &m_pFontBig);
  226.  
  227.     LoadObjectResources(m_pDevice);
  228.     LoadMapObjectResources(m_pDevice);
  229.     LoadUnitResources(m_pDevice);
  230.     LoadBuildingResources(m_pDevice);
  231.     LoadPlayerResources(m_pDevice);
  232.     LoadEffectResources(m_pDevice);
  233.     LoadParticleResources(m_pDevice);
  234.  
  235.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  236.  
  237.     m_camera.Init(m_pDevice);
  238.     m_camera.m_fov = 0.6f;
  239.     m_camera.m_radius = 50.0f;
  240.  
  241.     D3DXCreateLine(m_pDevice, &m_pLine);
  242.  
  243.     //Set sampler state
  244.     for(int i=0;i<8;i++)
  245.     {
  246.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  247.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  248.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  249.     }
  250.  
  251.     //Create Fog-of-war textures
  252.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisibleTexture, NULL)))debug.Print("Failed to create texture: m_pVisibleTexture");
  253.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisitedTexture, NULL)))debug.Print("Failed to create texture: m_pVisitedTexture");
  254.  
  255.     //Fog-of-war Shaders
  256.     m_visitedShader.Init(m_pDevice, "shaders/visited.ps", PIXEL_SHADER);
  257.     m_FogOfWarShader.Init(m_pDevice, "shaders/FogOfWar.ps", PIXEL_SHADER);
  258.     m_firstFogOfWar = true;
  259.  
  260.     //Create Minimap
  261.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pMiniMap, NULL)))debug.Print("Failed to create texture: m_pMiniMap");
  262.     if(FAILED(D3DXCreateTextureFromFile(m_pDevice, "textures/minimap.dds", &m_pMiniMapBorder)))debug.Print("Could not load minimap.dds");
  263.     m_miniMapShader.Init(m_pDevice, "shaders/minimap.ps", PIXEL_SHADER);
  264.     RECT r = {611, 9, 791, 189};
  265.     m_miniMapRect = r;
  266.  
  267.     //Menu
  268.     D3DXCreateTextureFromFile(m_pDevice, "textures/menu.jpg", &m_pMenuTexture);
  269.     D3DXCreateTextureFromFile(m_pDevice, "textures/menuButtons.dds", &m_pMenuButtons);
  270.  
  271.     //Sprite 
  272.     D3DXCreateSprite(m_pDevice, &m_pSprite);
  273.     
  274.     //Init Intro
  275.     m_sound.Init(m_mainWindow);
  276.     m_pIntroSong = new MP3();
  277.     m_pIntroSong->LoadSong(L"music/intro.mp3");
  278.     m_pIntroSong->Play();
  279.  
  280.     m_pIntroMovie = new AVI();
  281.     m_pIntroMovie->Load("avi/intro.avi", m_pDevice);
  282.     m_pIntroMovie->Play();
  283.     m_playingIntro = true;
  284.  
  285.     m_songs[0].LoadSong(L"music/song1.mp3");
  286.     m_songs[1].LoadSong(L"music/song2.mp3");
  287.     
  288.     for(int i=0;i<2;i++)
  289.     {
  290.         m_songs[i].Play();
  291.         m_songs[i].SetVolume(0.0f);
  292.     }    
  293.  
  294.     m_volumes[0] = m_volumes[1] = 0.0f;
  295.     m_playingSong = -1;
  296.  
  297.     return S_OK;
  298. }
  299.  
  300. void APPLICATION::Load(int mode)
  301. {
  302.     if(mode == SINGLE_PLAYER)
  303.     {
  304.         //Init Terrain
  305.         m_terrain.Init(m_pDevice, INTPOINT(150,150));
  306.  
  307.         //Add Players
  308.         AddPlayers(4);
  309.     }
  310.     else if(mode == MULTI_PLAYER)
  311.     {
  312.  
  313.     }
  314.  
  315.     m_gameOver = false;
  316.     m_firstFogOfWar = true;
  317. }
  318.  
  319. HRESULT APPLICATION::Update(float deltaTime)
  320. {
  321.     //Intro
  322.     if(m_playingIntro)
  323.     {
  324.         m_pIntroMovie->Update(deltaTime);
  325.  
  326.         if(m_pIntroMovie->Done() || KEYDOWN(VK_SPACE) || KEYDOWN(VK_RETURN))
  327.         {
  328.             m_playingIntro = false;
  329.             delete m_pIntroMovie;
  330.             m_pIntroMovie = NULL;
  331.             delete m_pIntroSong;
  332.             m_pIntroSong = NULL;
  333.             m_playingSong = 0;
  334.             m_menu = true;
  335.         }
  336.     }
  337.     else if(m_menu)
  338.     {
  339.         m_mouse.Update(NULL);
  340.     }
  341.     else if(m_gameOver)
  342.     {
  343.         m_gameOverTime -= deltaTime;
  344.         if(m_gameOverTime <= 0.0f)
  345.             m_menu = true;
  346.     }
  347.     else
  348.     {
  349.         //Remove dead effects
  350.         std::vector<EFFECT*>::iterator i;
  351.  
  352.         for(i=effects.begin();i != effects.end();)
  353.         {
  354.             if((*i)->isDead())
  355.             {
  356.                 delete (*i);
  357.                 effects.erase(i);
  358.             }
  359.             else 
  360.             {
  361.                 (*i)->Update(deltaTime * m_gameSpeed);
  362.                 i++;
  363.             }
  364.         }
  365.         
  366.         //Update Players
  367.         int numAlivePlayers = 0;
  368.  
  369.         for(int i=0;i<m_players.size();i++)
  370.             if(m_players[i] != NULL)
  371.             {
  372.                 m_players[i]->UpdateMapObjects(deltaTime * m_gameSpeed);
  373.  
  374.                 if(m_players[i]->Alive())
  375.                     numAlivePlayers++;
  376.             }
  377.  
  378.         if(numAlivePlayers <= 1 || !m_players[m_thisPlayer]->Alive())
  379.         {
  380.             m_gameOver = true;
  381.             m_gameOverTime = 5.0f;
  382.         }
  383.  
  384.         //Update Fog-of-War
  385.         FogOfWar();    
  386.  
  387.         //Control camera
  388.         m_camera.Update(m_mouse, m_terrain, deltaTime);
  389.         m_mouse.Update(&m_terrain);
  390.  
  391.         //Update SightMatrices & visible variables
  392.         if(m_terrain.m_updateSight)
  393.         {
  394.             m_terrain.m_updateSight = false;
  395.  
  396.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  397.                 m_terrain.UpdateSightMatrices(m_players[m_thisPlayer]->m_mapObjects);
  398.  
  399.             for(int i=0;i<m_players.size();i++)
  400.                 if(m_players[i] != NULL)
  401.                     m_players[i]->IsMapObjectsVisible();
  402.  
  403.             //Update Minimap        
  404.             UpdateMiniMap();
  405.         }
  406.  
  407.         //Order units of m_thisPlayer's team around
  408.         if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  409.         {
  410.             m_players[m_thisPlayer]->UnitOrders(m_mouse, m_players, m_camera);
  411.  
  412.             if(m_players[m_thisPlayer]->InBattle())
  413.                 m_playingSong = 1;
  414.             else m_playingSong = 0;
  415.         }
  416.  
  417.         //Update m_sound        
  418.         for(int i=0;i<2;i++)
  419.         {
  420.             if(!m_songs[i].IsPlaying())
  421.                 m_songs[i].Play();
  422.  
  423.             if(m_playingSong == i)
  424.                 m_volumes[i] += deltaTime * 0.2f;
  425.             else if(i == 0 && m_volumes[1] > 0.75f || i == 1 && m_volumes[0] > 0.75f)
  426.                 m_volumes[i] -= deltaTime * 0.2f;
  427.  
  428.             if(m_volumes[i] > 1.0f)m_volumes[i] = 1.0f;
  429.             if(m_volumes[i] < 0.0f)m_volumes[i] = 0.0f;
  430.  
  431.             m_songs[i].SetVolume(m_volumes[i]);
  432.         }
  433.  
  434.     }
  435.  
  436.     //Keyboard input
  437.     if(KEYDOWN(VK_ESCAPE))
  438.     {
  439.         Quit();
  440.     }
  441.  
  442.     //Group Assignment
  443.     Groups();
  444.  
  445.     return S_OK;
  446. }    
  447.  
  448. HRESULT APPLICATION::Render()
  449. {
  450.     // Clear the viewport
  451.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  452.  
  453.     // Begin the scene 
  454.     if(SUCCEEDED(m_pDevice->BeginScene()))
  455.     {
  456.         if(m_playingIntro)
  457.         {
  458.             D3DXMATRIX sca;
  459.             D3DXMatrixScaling(&sca, 2.0f, 2.0f, 1.0f);
  460.  
  461.             m_pSprite->SetTransform(&sca);
  462.             m_pSprite->Begin(0);
  463.             m_pSprite->Draw(m_pIntroMovie->m_pCurrentFrame, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  464.             m_pSprite->End();
  465.  
  466.             D3DXMatrixIdentity(&sca);
  467.             m_pSprite->SetTransform(&sca);
  468.         }
  469.         else if(m_menu)
  470.         {
  471.             MainMenu();
  472.             m_mouse.Paint();
  473.         }
  474.         else if(m_gameOver)
  475.         {
  476.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  477.             {
  478.                 RECT rc = {0, 280, 800, 320};
  479.                 if(m_players[m_thisPlayer]->Alive())
  480.                     m_pFontBig->DrawText(NULL, "You Win!", -1, &rc, DT_CENTER | DT_TOP | DT_NOCLIP, 0xffffffff);
  481.                 else m_pFontBig->DrawText(NULL, "You Lose!", -1, &rc, DT_CENTER | DT_TOP | DT_NOCLIP, 0xffffffff);
  482.             }
  483.         }
  484.         else
  485.         {
  486.             //Render terrain
  487.             m_terrain.Render(m_camera);
  488.  
  489.             //Render units and buildings
  490.             for(int i=0;i<m_players.size();i++)
  491.                 if(m_players[i] != NULL)
  492.                     m_players[i]->RenderMapObjects(m_camera);
  493.  
  494.             //Render Effects
  495.             for(int i=0;i<effects.size();i++)
  496.                 if(effects[i] != NULL)
  497.                     effects[i]->Render();
  498.  
  499.             //Select units, menu etc
  500.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  501.             {
  502.                 m_players[m_thisPlayer]->PaintSelectedMapObjects(m_camera);
  503.                 m_players[m_thisPlayer]->PlaceBuilding(m_mouse, m_camera);
  504.                 m_players[m_thisPlayer]->Select(m_mouse);
  505.                 m_players[m_thisPlayer]->Menu(m_mouse);
  506.             }
  507.  
  508.             //Render Minimap
  509.             RenderMiniMap(m_miniMapRect);
  510.             
  511.             m_mouse.Paint();
  512.         }
  513.  
  514.         // End the scene.
  515.         m_pDevice->EndScene();
  516.         m_pDevice->Present(0, 0, 0, 0);
  517.     }
  518.  
  519.     return S_OK;
  520. }
  521.  
  522. HRESULT APPLICATION::Cleanup()
  523. {
  524.     try
  525.     {
  526.         m_terrain.Release();
  527.  
  528.         if(m_pIntroSong)m_pIntroSong->Release();
  529.         if(m_pIntroMovie)m_pIntroMovie->Release();
  530.  
  531.         m_songs[0].Release();
  532.         m_songs[1].Release();
  533.  
  534.         UnloadObjectResources();
  535.         UnloadMapObjectResources();
  536.         UnloadUnitResources();
  537.         UnloadBuildingResources();
  538.         UnloadPlayerResources();
  539.         UnloadEffectResources();
  540.         UnloadParticleResources();
  541.  
  542.         if(m_pVisibleTexture)m_pVisibleTexture->Release();
  543.         if(m_pVisitedTexture)m_pVisitedTexture->Release();
  544.         if(m_pMiniMap)m_pMiniMap->Release();
  545.         if(m_pMiniMapBorder)m_pMiniMapBorder->Release();
  546.         if(m_pMenuTexture)m_pMenuTexture->Release();
  547.         if(m_pMenuButtons)m_pMenuButtons->Release();
  548.  
  549.         for(int i=0;i<m_players.size();i++)
  550.             if(m_players[i] != NULL)
  551.                 delete m_players[i];
  552.         m_players.clear();
  553.  
  554.         m_pSprite->Release();
  555.         m_pLine->Release();
  556.  
  557.         m_pFont->Release();
  558.         m_pFontBig->Release();
  559.  
  560.         debug.Print("Application terminated");
  561.     }
  562.     catch(...){}
  563.  
  564.     return S_OK;
  565. }
  566.  
  567. HRESULT APPLICATION::Quit()
  568. {
  569.     ::DestroyWindow(m_mainWindow);
  570.     ::PostQuitMessage(0);
  571.     return S_OK;
  572. }
  573.  
  574. void APPLICATION::AddPlayers(int noPlayers)
  575. {
  576.     m_thisPlayer = 0;
  577.  
  578.     for(int i=0;i<m_players.size();i++)
  579.         if(m_players[i] != NULL)
  580.             delete m_players[i];
  581.     m_players.clear();
  582.  
  583.     INTPOINT startLocations[] = {INTPOINT(30,30), INTPOINT(120,30), INTPOINT(30,120), INTPOINT(120,120)};
  584.  
  585.     D3DXVECTOR4 teamCols[] = {D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f), D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f),
  586.                               D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f), D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f)};
  587.     
  588.     int controllers[] = {HUMAN, COMPUTER, COMPUTER, COMPUTER};
  589.  
  590.     if(noPlayers < 2)noPlayers = 2;
  591.     if(noPlayers > 4)noPlayers = 4;
  592.  
  593.     for(int i=0;i<noPlayers;i++)
  594.     {
  595.         m_terrain.Progress("Creating Players", i / (float)noPlayers);
  596.         m_players.push_back(new PLAYER(i, controllers[i], teamCols[i], startLocations[i], &m_terrain, m_pDevice));    
  597.     }
  598.  
  599.     //Center camera focus on the team...
  600.     m_camera.m_focus = m_terrain.GetWorldPos(m_players[m_thisPlayer]->GetCenter());
  601. }
  602.  
  603. void APPLICATION::FogOfWar()
  604. {
  605.     try
  606.     {
  607.         if(m_pVisibleTexture == NULL || m_pVisitedTexture == NULL)return;
  608.         
  609.         //Set orthogonal rendering view & projection
  610.         m_terrain.SetOrthogonalView();
  611.  
  612.         //Retrieve the surface of the back buffer
  613.         IDirect3DSurface9 *backSurface = NULL;
  614.         m_pDevice->GetRenderTarget(0, &backSurface);
  615.  
  616.         //Render the Visible Texture here...
  617.         {
  618.             //Set texture stages and Renderstates
  619.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  620.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
  621.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_ADD);
  622.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  623.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
  624.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
  625.  
  626.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  627.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  628.             m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  629.             m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTALPHA);
  630.             
  631.             //Get the surface of the m_pVisibleTexture
  632.             IDirect3DSurface9 *visibleSurface = NULL;            
  633.             m_pVisibleTexture->GetSurfaceLevel(0, &visibleSurface);            
  634.  
  635.             //Set render target to the visible surface
  636.             m_pDevice->SetRenderTarget(0, visibleSurface);
  637.  
  638.             //Clear render target to black
  639.             m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  640.  
  641.             m_pDevice->BeginScene();
  642.  
  643.             //Render the sightTexture for all map objects in m_thisPlayer.
  644.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  645.                 for(int u=0;u<m_players[m_thisPlayer]->m_mapObjects.size();u++)
  646.                     if(m_players[m_thisPlayer]->m_mapObjects[u] != NULL)
  647.                         m_players[m_thisPlayer]->m_mapObjects[u]->RenderSightMesh();
  648.  
  649.             m_pDevice->EndScene();
  650.  
  651.             //Restore renderstates etc.
  652.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  653.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  654.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  655.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  656.  
  657.             //Release visible surface
  658.             visibleSurface->Release();
  659.         }
  660.  
  661.         //Render the Visited Texture here...
  662.         {
  663.             IDirect3DSurface9 *visitedSurface = NULL;
  664.             m_pVisitedTexture->GetSurfaceLevel(0, &visitedSurface);
  665.  
  666.             //Render to the visted texture
  667.             m_pDevice->SetRenderTarget(0, visitedSurface);
  668.             if(m_firstFogOfWar)
  669.             {
  670.                 m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  671.                 m_firstFogOfWar = false;
  672.             }
  673.  
  674.             m_pDevice->BeginScene();
  675.             m_pDevice->SetTexture(0, m_pVisibleTexture);
  676.             m_pDevice->SetTexture(1, m_pVisitedTexture);
  677.  
  678.             m_pSprite->Begin(0);
  679.             m_visitedShader.Begin();
  680.             m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  681.             m_pSprite->End();
  682.             m_visitedShader.End();
  683.  
  684.             m_pDevice->EndScene();
  685.         
  686.             //Release visited surface
  687.             visitedSurface->Release();
  688.         }
  689.  
  690.         //Render the final FogOfWarTexture
  691.         {
  692.             //Get and set surface of the FogOfWarTexture...
  693.             IDirect3DSurface9 *FogOfWarSurface = NULL;
  694.             m_terrain.m_pFogOfWarTexture->GetSurfaceLevel(0, &FogOfWarSurface);
  695.             m_pDevice->SetRenderTarget(0, FogOfWarSurface);
  696.  
  697.             m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  698.             m_pDevice->BeginScene();
  699.  
  700.             //Set Textures
  701.             m_pDevice->SetTexture(0, m_pVisibleTexture);
  702.             m_pDevice->SetTexture(1, m_pVisitedTexture);
  703.             m_pDevice->SetTexture(2, m_terrain.m_pLightMap);
  704.  
  705.             //Draw to the Fog-of-War texture
  706.             m_pSprite->Begin(0);
  707.             m_FogOfWarShader.Begin();
  708.             m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  709.             m_pSprite->End();
  710.             m_FogOfWarShader.End();
  711.  
  712.             m_pDevice->EndScene();
  713.             //Release fog of war surface
  714.             FogOfWarSurface->Release();
  715.         }
  716.  
  717.         //Reset render target to back buffer
  718.         m_pDevice->SetRenderTarget(0, backSurface);
  719.         backSurface->Release();        
  720.     }
  721.     catch(...)
  722.     {
  723.         debug.Print("Error in APPLICATION::FogOfWar()");
  724.     }
  725. }
  726.  
  727. void APPLICATION::UpdateMiniMap()
  728. {
  729.     //Retrieve the surface of the back buffer
  730.     IDirect3DSurface9 *backSurface = NULL;
  731.     m_pDevice->GetRenderTarget(0, &backSurface);
  732.  
  733.     //Get and set surface of the FogOfWarTexture...
  734.     IDirect3DSurface9 *minimapSurface = NULL;
  735.     m_pMiniMap->GetSurfaceLevel(0, &minimapSurface);
  736.     m_pDevice->SetRenderTarget(0, minimapSurface);
  737.  
  738.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  739.     m_pDevice->BeginScene();
  740.  
  741.     //Set Textures
  742.     m_pDevice->SetTexture(0, m_terrain.m_pLandScape);
  743.     m_pDevice->SetTexture(1, m_terrain.m_pFogOfWarTexture);
  744.  
  745.     //Draw to the minimap texture
  746.     m_pSprite->Begin(0);
  747.     m_miniMapShader.Begin();
  748.     m_pSprite->Draw(m_terrain.m_pLandScape, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  749.     m_pSprite->End();
  750.     m_miniMapShader.End();
  751.  
  752.     m_pDevice->EndScene();
  753.     //Draw units and buildings in the player team color
  754.     for(int p=0;p<m_players.size();p++)
  755.         if(m_players[p] != NULL)
  756.         {
  757.             std::vector<D3DRECT> rects;
  758.  
  759.             //Get rectangles in "Minimap Space"
  760.             for(int m=0;m<m_players[p]->m_mapObjects.size();m++)
  761.                 if(m_players[p]->m_mapObjects[m] != NULL && !m_players[p]->m_mapObjects[m]->m_dead)
  762.                     if(!m_players[p]->m_mapObjects[m]->m_isBuilding)
  763.                     {
  764.                         INTPOINT mappos = m_players[p]->m_mapObjects[m]->m_mappos;
  765.  
  766.                         //Only add units standing on visible tiles
  767.                         if(m_terrain.m_pVisibleTiles[mappos.x + mappos.y * m_terrain.m_size.x])
  768.                         {
  769.                             INTPOINT pos(256.0f * (mappos.x / (float)m_terrain.m_size.x), 
  770.                                          256.0f * (mappos.y / (float)m_terrain.m_size.y));
  771.  
  772.                             rects.push_back(SetRect(pos.x - 1, pos.y - 1, 
  773.                                                     pos.x + 2, pos.y + 2));
  774.                         }
  775.                     }
  776.                     else 
  777.                     {
  778.                         RECT r = m_players[p]->m_mapObjects[m]->GetMapRect(0);
  779.  
  780.                         //Add only those parts of the buildings standing on visited tiles
  781.                         for(int y=r.top;y<=r.bottom;y++)
  782.                             for(int x=r.left;x<=r.right;x++)
  783.                                 if(m_terrain.m_pVisitedTiles[x + y * m_terrain.m_size.x])
  784.                                 {
  785.                                     INTPOINT pos(256.0f * (x / (float)m_terrain.m_size.x), 
  786.                                                  256.0f * (y / (float)m_terrain.m_size.y));
  787.  
  788.                                     rects.push_back(SetRect(pos.x - 1, pos.y - 1, 
  789.                                                             pos.x + 2, pos.y + 2));
  790.                                 }
  791.                     }
  792.  
  793.             //Clear rectangles using the team color
  794.             if(!rects.empty())
  795.             {
  796.                 D3DXCOLOR c = D3DCOLOR_XRGB((int)(m_players[p]->m_teamColor.x * 255),
  797.                                             (int)(m_players[p]->m_teamColor.y * 255),
  798.                                             (int)(m_players[p]->m_teamColor.z * 255));
  799.                 
  800.                 m_pDevice->Clear(rects.size(), &rects[0], D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, c, 1.0f, 0);
  801.             }
  802.         }
  803.  
  804.     //Reset render target to back buffer
  805.     m_pDevice->SetRenderTarget(0, backSurface);
  806.  
  807.     //Release surfaces
  808.     backSurface->Release();
  809.     minimapSurface->Release();
  810. }
  811.  
  812. void APPLICATION::RenderMiniMap(RECT dest)
  813. {
  814.     float width = dest.right - dest.left;
  815.     float height = dest.bottom - dest.top;
  816.  
  817.     D3DXVECTOR2 scale = D3DXVECTOR2(width / 256.0f, 
  818.                                     height / 256.0f);
  819.     D3DXMATRIX sca;
  820.     D3DXMatrixScaling(&sca, scale.x, scale.y, 1.0f);
  821.     m_pSprite->SetTransform(&sca);
  822.  
  823.     m_pSprite->Begin(0);
  824.     m_pSprite->Draw(m_pMiniMap, NULL, NULL, &D3DXVECTOR3(dest.left / scale.x, dest.top / scale.y, 0.0f), 0xffffffff);
  825.     m_pSprite->End();
  826.  
  827.     D3DXMatrixIdentity(&sca);
  828.     m_pSprite->SetTransform(&sca);
  829.  
  830.     //Move camera using minimap
  831.     if(m_mouse.PressInRect(dest))
  832.     {
  833.         int x = ((m_mouse.x - dest.left) / width) * m_terrain.m_size.x;
  834.         int y = ((m_mouse.y - dest.top) / height) * m_terrain.m_size.y;
  835.  
  836.         m_camera.m_focus = m_terrain.GetWorldPos(INTPOINT(x, y));
  837.     }
  838.  
  839.     //Calculate m_camera frustum viewpoints
  840.     D3DXMATRIX view, proj, viewInverse;
  841.  
  842.     view = m_camera.GetViewMatrix();
  843.     proj = m_camera.GetProjectionMatrix();
  844.     
  845.     //fov_x & fov_y Determines the size of the frustum representation
  846.     float screenRatio = proj(0,0) / proj(1,1);
  847.     float fov_x = 0.4f;
  848.     float fov_y = fov_x * screenRatio;
  849.     
  850.     //Initialize the four rays
  851.     D3DXVECTOR3 org = D3DXVECTOR3(0.0f, 0.0f, 0.0f);    //Same origin
  852.  
  853.     //Four different directions
  854.     D3DXVECTOR3 dir[4] = {D3DXVECTOR3(-fov_x, fov_y, 1.0f),    
  855.                            D3DXVECTOR3(fov_x, fov_y, 1.0f),
  856.                           D3DXVECTOR3(fov_x, -fov_y, 1.0f),
  857.                           D3DXVECTOR3(-fov_x, -fov_y, 1.0f)};
  858.  
  859.     //Our resulting minimap coordinates
  860.     D3DXVECTOR2 points[5];
  861.  
  862.     //View matrix inverse
  863.     D3DXMatrixInverse(&viewInverse, 0, &view);
  864.     D3DXVec3TransformCoord(&org, &org, &viewInverse);
  865.  
  866.     //Ground plane
  867.     D3DXPLANE plane;
  868.     D3DXPlaneFromPointNormal(&plane, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
  869.  
  870.     bool ok = true;
  871.  
  872.     //check where each ray intersects with the ground plane
  873.     for(int i=0;i<4 && ok;i++)
  874.     {
  875.         //Transform ray direction
  876.         D3DXVec3TransformNormal(&dir[i], &dir[i], &viewInverse);
  877.         D3DXVec3Normalize(&dir[i], &dir[i]);
  878.         dir[i] *= 1000.0f;
  879.  
  880.         //Find intersection point
  881.         D3DXVECTOR3 hit;
  882.         if(D3DXPlaneIntersectLine(&hit, &plane, &org, &dir[i]) == NULL)
  883.             ok = false;
  884.  
  885.         //Make sure the intersection point is on the positive side of the near plane
  886.         D3DXPLANE n = m_camera.m_frustum[4];
  887.         float distance = n.a * hit.x + n.b * hit.y + n.c * hit.z + n.d;
  888.         if(distance < 0.0f)ok = false;
  889.  
  890.         //Convert the intersection point to a minimap coordinate
  891.         if(ok)
  892.         {
  893.             points[i].x = (hit.x / (float)m_terrain.m_size.x) * width;
  894.             points[i].y = (-hit.z / (float)m_terrain.m_size.y) * height;
  895.         }
  896.     }
  897.  
  898.     //Set the end point to equal the starting point
  899.     points[4] = points[0];
  900.  
  901.     //Set viewport to destination rectangle only...
  902.     D3DVIEWPORT9 v1, v2;
  903.  
  904.     v1.X = dest.left;
  905.     v1.Y = dest.top;
  906.     v1.Width = width;
  907.     v1.Height = height;
  908.     v1.MinZ = 0.0f;
  909.     v1.MaxZ = 1.0f;
  910.  
  911.     m_pDevice->GetViewport(&v2);
  912.     m_pDevice->SetViewport(&v1);
  913.  
  914.     //Draw camera frustum in the minimap
  915.     if(ok)
  916.     {
  917.         m_pLine->SetWidth(1.0f);
  918.         m_pLine->SetAntialias(true);
  919.         m_pLine->Begin();
  920.         m_pLine->Draw(&points[0], 5, 0x44ffffff);
  921.         m_pLine->End();
  922.     }
  923.  
  924.     //Reset viewport
  925.     m_pDevice->SetViewport(&v2);
  926.  
  927.     //Draw minimap border
  928.     m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
  929.     m_pSprite->Draw(m_pMiniMapBorder, NULL, NULL, &D3DXVECTOR3(v2.Width - 256, 0.0f, 0.0f), 0xffffffff);
  930.     m_pSprite->End();
  931. }
  932.  
  933. void APPLICATION::MainMenu()
  934. {
  935.     m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
  936.     m_pSprite->Draw(m_pMenuTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  937.  
  938.     //Menu Buttons
  939.     for(int i=0;i<3;i++)
  940.     {
  941.         RECT src = {0, i * 60, 200, i * 60 + 30};
  942.         RECT dest = {600, i * 100 + 150, 800, i * 100 + 180};
  943.         if(m_mouse.Over(dest)){src.top += 30; src.bottom += 30;}
  944.  
  945.         m_pSprite->Draw(m_pMenuButtons, &src, NULL, &D3DXVECTOR3(dest.left, dest.top, 0.0f), 0xffffffff);
  946.         if(m_mouse.PressInRect(dest))
  947.         {
  948.             m_mouse.DisableInput(300);
  949.             m_menu = false;
  950.  
  951.             if(i == 0)
  952.                 Load(SINGLE_PLAYER);
  953.             else if(i == 1)
  954.             {
  955.                 //Load(MULTI_PLAYER);
  956.             }
  957.             else Quit();
  958.         }
  959.     }
  960.  
  961.     m_pSprite->End();
  962. }
  963.  
  964. void APPLICATION::Groups()
  965. {
  966.     if(GetTickCount() < m_groupTime)return;
  967.  
  968.     bool ctrl = KEYDOWN(VK_CONTROL);
  969.     int grp = -1;
  970.  
  971.     for(char c='0', int g=0;c<='9';c++, g++)
  972.         if(KEYDOWN(c))
  973.             grp = g;
  974.  
  975.     if(grp != -1 && m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)    
  976.     {
  977.         std::vector<MAPOBJECT*> *mapObjects = &m_players[m_thisPlayer]->m_mapObjects;
  978.  
  979.         for(int u=0;u<mapObjects->size();u++)
  980.         {
  981.             MAPOBJECT *mo = mapObjects->operator[](u);
  982.  
  983.             if(mo != NULL)
  984.             {
  985.                 if(ctrl)    //Assign group
  986.                 {
  987.                     if(mo->m_selected && mo->m_groupNumber != grp)
  988.                         mo->m_groupNumber = grp;                
  989.                     else if(!mo->m_selected && mo->m_groupNumber == grp)
  990.                         mo->m_groupNumber = -1;
  991.                 }
  992.                 else        //Select group
  993.                 {
  994.                     if(mo->m_groupNumber == grp)
  995.                         mo->m_selected = true;
  996.                     else mo->m_selected = false;
  997.                 }
  998.             }
  999.         }
  1000.  
  1001.         m_groupTime = GetTickCount() + 300;
  1002.     }
  1003. }